﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Rail.Commons;
using Rail.Commons.SerializeHelper;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;

namespace Yc.Commons
{
    public class Httper
    {
        // 保持 Cookie 为同一 Cookie 值。         
        protected CookieContainer craboCookie = new CookieContainer();
        protected string m_Uri = DefaultConfigXmlHelper.Instance.WebServerHost;         // 标识 Internet 资源的 URI 
        protected string m_Referer = null;         // 标识 Internet 资源请求的 Referer        
        protected string m_Headers = null;         // 标识 Internet 资源请求的 Header 
                                                   // 标识 Internet 资源请求的 Accept 
        protected string m_Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*";
        protected static List<string> m_Cookiesstrs = null;
        protected static WebHeaderCollection m_WebHeaderCollection = new WebHeaderCollection();
        protected string m_Cookiesstr = null;
        protected CookieCollection m_Cookieheader = null;

        protected string m_Method = null;         // 标识 Internet 资源请求的 Method 
        protected string m_Data = null;         // POST 请求时的数据 
        protected string m_CharacterSet = null;         // 响应的字符集 
        protected HttpStatusCode m_StatusCode;         // 响应状态 
        protected StringBuilder m_HtmlText = new StringBuilder();
        protected Image m_Image = null;

        private XmlDocument m_XmlDocument = new XmlDocument();
        private JObject m_JObject;

        private ResultTypesEnum m_ResultType = ResultTypesEnum.TUnKnow;

        public bool IsException = false;
        public int TimeOut = 20000;
        public Httper(String encode = "UTF-8")
        {
            doKeepLive();
            // 
            // TODO: 在此处添加构造函数逻辑 
            // 
            if (null == m_Cookiesstrs) m_Cookiesstrs = new List<string>();
            m_CharacterSet = encode;
        }

        static bool KeepLive = false;
        private static void doKeepLive()
        {
            if (KeepLive) return;
            KeepLive = true;
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    var httper = new Commons.Httper();
                    httper.Get4Live("getInfo", (x) =>
                    {
                        LogHelper.Info("keep live");
                    });
                    System.Threading.Thread.Sleep(1000 * 60 * 20);
                }
            });
        }
        private void Get4Live(string url, Action<object> act, ResultTypesEnum resultType = ResultTypesEnum.TJson)
        {
            m_ResultType = resultType;
            OpenRequest(m_Uri + "/" + url, url);
            act(GetResult());
        }
        public void Get(string url, Action<object> act, ResultTypesEnum resultType = ResultTypesEnum.TJson)
        {
            m_ResultType = resultType;
            bool reqOK = false;
            Task.Factory.StartNew(() =>
            {
                reqOK = OpenRequest(m_Uri + "/" + url, url);
            }).ContinueWith(t =>
            {
                act(GetResult());
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
        public void Post(string url, string requestData, Action<object> act, ResultTypesEnum resultType = ResultTypesEnum.TJson)
        {
            m_ResultType = resultType;
            bool reqOK = false;
            Task.Factory.StartNew(() =>
            {
                reqOK = OpenRequestNew(m_Uri + "/" + url, url, requestData);
            }).ContinueWith(t =>
            {
                if (!reqOK)
                {
                    act("Error");
                    return;
                }
                act(GetResult());
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
        private void InitResult()
        {
            m_HtmlText.Remove(0, m_HtmlText.Length);
            this.m_JObject = null;
            this.m_XmlDocument.RemoveAll();
            m_Image = null;
        }
        private object GetResult()
        {
            if (m_ResultType == ResultTypesEnum.TImage) return this.m_Image;
            else if (m_ResultType == ResultTypesEnum.TJson) return this.m_JObject;
            else if (m_ResultType == ResultTypesEnum.TXml) return this.m_XmlDocument;
            else return this.m_HtmlText;

        }
        /// <summary> 
        /// 对 Internet 资源发起 GET 请求 
        /// </summary> 
        /// <param name="requestUriString">标识 Internet 资源的URI</param> 
        /// <param name="requestReferer">标识 Internet 资源请求的Referer</param> 
        private bool OpenRequest(string requestUriString, string requestReferer)
        {
            InitResult();
            m_Uri = requestUriString;
            m_Referer = requestReferer;
            m_Method = "GET";
            return OpenRequest();
        }
        /// <summary> 
        /// 对 Internet 资源发起 GET 请求 
        /// </summary> 
        /// <param name="requestUriString">标识 Internet资源的URI</param> 
        /// <param name="requestReferer">标识 Internet资源请求的Referer</param> 
        /// <param name="requestMethod">标识 Internet资源请求的 Post 数据</param> 
        private bool OpenRequest(string requestUriString, string requestReferer, string requestData)
        {
            InitResult();
            m_Uri = requestUriString;
            m_Referer = requestReferer;
            m_Data = requestData;
            m_Method = "POST";
            return OpenRequest();
        }
        private bool OpenRequestNew(string requestUriString, string requestReferer, string requestData)
        {
            InitResult();
            m_Uri = requestUriString;
            m_Referer = requestReferer;
            m_Data = requestData;
            m_Method = "POST";
            return OpenRequestNew();
        }
        public void SetCookieheader(string Cookie)
        {
            m_Cookiesstrs.Add(Cookie);
        }

        public void SetToken(string token)
        {
            m_WebHeaderCollection.Add("Authorization", token);
        }

        /// <summary> 
        public string GetCookieheader()
        {
            return m_Cookiesstr;
        }

        public void SetCookie(CookieCollection Cookie)
        {
            craboCookie.Add(Cookie);
        }
        public CookieCollection GetCookie()
        {
            return m_Cookieheader;
        }

        /// 对 Internet 资源发起请求 
        /// </summary> 
        /// <returns></returns> 
        private bool OpenRequest()
        {
            // 清空已保留代码 
            m_HtmlText.Remove(0, m_HtmlText.Length);
            // 创建 HttpWebRequest 实例 
            HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(m_Uri);
            // 设置跟随重定向 
            Request.AllowAutoRedirect = true;
            #region 判断 Uri 资源类型
            {
                Regex _RegexUri = new Regex("^https://", RegexOptions.IgnoreCase);
                if (_RegexUri.IsMatch(m_Uri))
                    ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
            };
            #endregion

            //System.Net.WebProxy proxy = new System.Net.WebProxy("172.168.2.254:8080", true);
            //proxy.Credentials = new NetworkCredential("linxy", "lxy123456");
            //Request.Proxy = proxy;

            Request.Timeout = TimeOut;
            Request.Method = m_Method;
            Request.Accept = m_Accept;
            Request.UserAgent = "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.2) Gecko/20090803 Fedora/3.5.2-2.fc11 Firefox/3.5.2";
            Request.Referer = m_Referer;
            Request.Proxy = null;
            Request.CookieContainer = craboCookie;
            Request.Headers = m_WebHeaderCollection;
            foreach (var cookie in m_Cookiesstrs)
            {
                Request.Headers.Add("Cookie", cookie);
            }

            if (m_Method == "POST")
            {
                #region 请求为 POST
                Request.ContentType = "application/x-www-form-urlencoded";

                byte[] Bytes = Encoding.GetEncoding(m_CharacterSet).GetBytes(m_Data);
                Request.ContentLength = Bytes.Length;
                using (Stream writer = Request.GetRequestStream())
                {
                    writer.Write(Bytes, 0, Bytes.Length);
                    writer.Close();
                }
                #endregion
            }
            #region 读取返回数据
            // 设置返回值变量 
            bool bResult = true;
            try
            {
                HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();
                m_Cookiesstr = Response.Headers["Set-Cookie"]?.ToString();
                m_Cookieheader = Request.CookieContainer.GetCookies(new Uri(m_Uri));
                // 获取状态值 
                m_StatusCode = Response.StatusCode;
                if (m_StatusCode == HttpStatusCode.OK)
                {

                    // 判断页面编码 
                    var rType = this.m_ResultType;
                    switch (rType)
                    {
                        case ResultTypesEnum.TJson:
                            using (Stream reader = Response.GetResponseStream())
                            {
                                StreamReader sr = new StreamReader(reader, Encoding.GetEncoding(CharacterSet));
                                m_HtmlText.Append(sr.ReadToEnd());
                                sr.Close();
                                reader.Close();
                                m_JObject = (JObject)JsonConvert.DeserializeObject(m_HtmlText.ToString());
                            }
                            break;
                        case ResultTypesEnum.TImage:
                            using (Stream reader = Response.GetResponseStream())
                            {
                                StreamReader sr = new StreamReader(reader, Encoding.GetEncoding(CharacterSet));
                                m_HtmlText.Append(sr.ReadToEnd());
                                sr.Close();
                                reader.Close();
                                
                                JObject jo = (JObject)JsonConvert.DeserializeObject(m_HtmlText.ToString());
                                var imgObj = jo["img"];
                                var imgString = imgObj.ToString();
                                m_Image = ToImage(imgString);
                            }
                            break;
                        case ResultTypesEnum.TXml:
                            using (Stream reader = Response.GetResponseStream())
                            {
                                StreamReader sr = new StreamReader(reader, Encoding.GetEncoding(CharacterSet));
                                m_HtmlText.Append(sr.ReadToEnd());
                                sr.Close();
                                reader.Close();
                                try
                                {
                                    m_XmlDocument.RemoveAll();
                                    m_XmlDocument.LoadXml(m_HtmlText.ToString().Trim());
                                }
                                catch { }
                            }
                            break;
                        case ResultTypesEnum.TUnKnow:
                            using (Stream reader = Response.GetResponseStream())
                            {
                                StreamReader sr = new StreamReader(reader, Encoding.GetEncoding(CharacterSet));
                                m_HtmlText.Append(sr.ReadToEnd());
                                sr.Close();
                                reader.Close();
                            }
                            break;
                    }
                }
                else
                    bResult = false;
            }
            catch (Exception pEx)
            {
                IsException = true;
                m_HtmlText.Append(pEx.Message);
                return false;
            }
            #endregion
            return bResult;
        }
        private bool OpenRequestNew()
        {
            // 清空已保留代码 
            m_HtmlText.Remove(0, m_HtmlText.Length);
            // 创建 HttpWebRequest 实例 
            HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(m_Uri);
            // 设置跟随重定向 
            Request.AllowAutoRedirect = true;
            #region 判断 Uri 资源类型
            {
                Regex _RegexUri = new Regex("^https://", RegexOptions.IgnoreCase);
                if (_RegexUri.IsMatch(m_Uri))
                    ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
            };
            #endregion

            //System.Net.WebProxy proxy = new System.Net.WebProxy("172.168.2.254:8080", true);
            //proxy.Credentials = new NetworkCredential("linxy", "lxy123456");
            //Request.Proxy = proxy;

            Request.Timeout = TimeOut;
            Request.Method = m_Method;
            Request.Accept = m_Accept;
            Request.UserAgent = "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.2) Gecko/20090803 Fedora/3.5.2-2.fc11 Firefox/3.5.2";
            Request.Referer = m_Referer;
            Request.Proxy = null;

            foreach (var cookie in m_Cookiesstrs)
            {
                Request.Headers.Add("Cookie", cookie);
            }

            if (m_Method == "POST")
            {
                #region 请求为 POST
                Request.ContentType = "application/json";

                byte[] Bytes = Encoding.GetEncoding(m_CharacterSet).GetBytes(m_Data);
                Request.ContentLength = Bytes.Length;
                using (Stream writer = Request.GetRequestStream())
                {
                    writer.Write(Bytes, 0, Bytes.Length);
                    writer.Close();
                }
                #endregion
            }
            #region 读取返回数据
            // 设置返回值变量 
            bool bResult = true;
            try
            {
                HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();

                // 获取状态值 
                m_StatusCode = Response.StatusCode;
                if (m_StatusCode == HttpStatusCode.OK)
                {
                    // 判断页面编码 
                    var rType = this.m_ResultType;
                    switch (rType)
                    {
                        case ResultTypesEnum.TJson:
                            using (Stream reader = Response.GetResponseStream())
                            {
                                StreamReader sr = new StreamReader(reader, Encoding.GetEncoding(CharacterSet));
                                m_HtmlText.Append(sr.ReadToEnd());
                                sr.Close();
                                reader.Close();
                                m_JObject = (JObject)JsonConvert.DeserializeObject(m_HtmlText.ToString());
                            }
                            break;
                        case ResultTypesEnum.TImage:
                            using (Stream reader = Response.GetResponseStream())
                            {
                                StreamReader sr = new StreamReader(reader, Encoding.GetEncoding(CharacterSet));
                                m_HtmlText.Append(sr.ReadToEnd());
                                sr.Close();
                                reader.Close();

                                JObject jo = (JObject)JsonConvert.DeserializeObject(m_HtmlText.ToString());
                                var imgObj = jo["img"];
                                var imgString = imgObj.ToString();
                                m_Image = ToImage(imgString);
                            }
                            break;
                        case ResultTypesEnum.TXml:
                            using (Stream reader = Response.GetResponseStream())
                            {
                                StreamReader sr = new StreamReader(reader, Encoding.GetEncoding(CharacterSet));
                                m_HtmlText.Append(sr.ReadToEnd());
                                sr.Close();
                                reader.Close();
                                try
                                {
                                    m_XmlDocument.RemoveAll();
                                    m_XmlDocument.LoadXml(m_HtmlText.ToString().Trim());
                                }
                                catch { }
                            }
                            break;
                        case ResultTypesEnum.TUnKnow:
                            using (Stream reader = Response.GetResponseStream())
                            {
                                StreamReader sr = new StreamReader(reader, Encoding.GetEncoding(CharacterSet));
                                m_HtmlText.Append(sr.ReadToEnd());
                                sr.Close();
                                reader.Close();
                            }
                            break;
                    }
                    m_Cookiesstr = craboCookie.GetCookieHeader(Request.RequestUri); //把cookies转换成字符串
                }
                else
                    bResult = false;
            }
            catch (Exception pEx)
            {
                IsException = true;
                m_HtmlText.Append(pEx.Message);
                return false;
            }
            #endregion
            return bResult;
        }

        public XmlDocument Doc
        {
            get
            {
                return m_XmlDocument;
            }
        }


        /// <summary> 
        /// 获取或设置 Uri 资源字符集 
        /// </summary> 
        public string CharacterSet
        {
            get
            {
                return m_CharacterSet;
            }
            set
            {
                m_CharacterSet = value;
            }
        }
        /// <summary> 
        /// 获取或设置 Uri 资源标识 
        /// </summary> 
        public string RequestUriString
        {
            get
            {
                return m_Uri;
            }
            set
            {
                m_Uri = value;
            }
        }
        /// <summary> 
        /// 获取或设置 Uri 资源请求 Accept 
        /// </summary> 
        public string Accept
        {
            get
            {
                return m_Accept;
            }
            set
            {
                m_Accept = value;
            }
        }

        public JObject Json { get => m_JObject; }

        protected class TrustAllCertificatePolicy : System.Net.ICertificatePolicy
        {
            public static bool TrustAllCertificateCallback(object sender,
            X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
            {
                return true;
            }

            public bool CheckValidationResult(System.Net.ServicePoint srvPoint,
            X509Certificate certificate, System.Net.WebRequest request, int
            certificateProblem)
            {
                return true;
            }
        }

        public enum ResultTypesEnum
        {
            TUnKnow = 0,
            TJson = 1,
            TXml = 2,
            TImage
        }

        private Image ToImage(string imgString)
        {

            byte[] bytes = Convert.FromBase64String(imgString);

            MemoryStream memStream = new MemoryStream(bytes);

            
            Image img =  new System.Drawing.Bitmap(memStream);
            return img;
        }
    }
}
